package com.kaibes.core.base.excetion;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;

public class ExceptionHandler implements UncaughtExceptionHandler{

    protected HashMap<String, String> buildVersion, buildData;
    private String exception;
    private static ExceptionHandler instance = new ExceptionHandler();
    private ExceptionListener exceptionListener;
    
    private ExceptionHandler() {
        buildVersion = new HashMap<>();
        buildData = new HashMap<>();
    }
    
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        if (exceptionListener != null && !exceptionListener.interceptException(e)) {
            collectDeviceInfo();
            saveCrashInfo2Map(e);
            exceptionListener.doWithException(exception, buildVersion, buildData);
            exception = "";
            buildVersion.clear();
            buildData.clear();
        }
    }
    
    public void setExceptionListener(ExceptionListener exceptionListener) {
        this.exceptionListener = exceptionListener;
    }
    
    /**
     * 收集设备参数信息
     *
     * @param ctx
     */
    protected void collectDeviceInfo() {
        buildData.put("os_name", System.getProperty("os.name"));
        buildData.put("os_arch", System.getProperty("os.arch"));
        buildData.put("os_version", System.getProperty("os.version"));
        buildData.put("file_separator", System.getProperty("file.separator"));
        buildData.put("path_separator", System.getProperty("path.separator"));
        buildData.put("line_separator", System.getProperty("line.separator"));
        buildData.put("user_name", System.getProperty("user.name"));
        buildData.put("user_home", System.getProperty("user.home"));
        buildData.put("user_dir", System.getProperty("user.dir"));
        
        buildVersion.put("java_version",System.getProperty("java.version"));
        buildVersion.put("java_vendor",System.getProperty("java.vendor"));
        buildVersion.put("java_vendor_url",System.getProperty("java.vendor.url"));
        buildVersion.put("java_home",System.getProperty("java.home"));
        buildVersion.put("java_vm_specification_version",System.getProperty("java.vm.specification.version"));
        buildVersion.put("java_vm_specification_vendor",System.getProperty("java.vm.specification.vendor"));
        buildVersion.put("java_vm_specification_name",System.getProperty("java.vm.specification.name"));
        buildVersion.put("java_vm_version",System.getProperty("java.vm.version"));
        buildVersion.put("java_vm_vendor",System.getProperty("java.vm.vendor"));
        buildVersion.put("java_vm_name",System.getProperty("java.vm.name"));
        buildVersion.put("java_specification_version",System.getProperty("java.specification.version"));
        buildVersion.put("java_specification_vendor",System.getProperty("java.specification.vendor"));
        buildVersion.put("java_specification_name",System.getProperty("java.specification.name"));
        buildVersion.put("java_class_version",System.getProperty("java.class.version"));
        buildVersion.put("java_class_path",System.getProperty("java.class.path"));
        buildVersion.put("java_library_path",System.getProperty("java.library.path"));
        buildVersion.put("java_io_tmpdir",System.getProperty("java.io.tmpdir"));
        buildVersion.put("java_compiler",System.getProperty("java.compiler"));
        buildVersion.put("java_ext_dirs",System.getProperty("java.ext.dirs"));
    }
    
    private void saveCrashInfo2Map(Throwable ex) {
        Writer writer = new StringWriter();
        PrintWriter printWriter = new PrintWriter(writer);
        ex.printStackTrace(printWriter);
        Throwable cause = ex.getCause();
        while (cause != null) {
            cause.printStackTrace(printWriter);
            cause = cause.getCause();
        }
        printWriter.close();
        exception = writer.toString();
    }
    
    public static ExceptionHandler getInstance() {
        return instance;
    }
    
    public final static String map2string(HashMap<String, String> buildData) {
        Iterator<Entry<String,String>> i = buildData.entrySet().iterator();
        if (! i.hasNext())
            return "{}";
        StringBuilder sb = new StringBuilder();
        sb.append('{');
        for (;;) {
            Entry<String,String> e = i.next();
            String key = e.getKey();
            String value = e.getValue();
            
            sb.append("\"");
            sb.append(key);
            sb.append("\"");
            sb.append(':');
            sb.append("\"");
            sb.append(value);
            sb.append("\"");
            if (! i.hasNext())
                return sb.append('}').toString();
            sb.append(',').append(' ');
        }
    }

}
